home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
tcl
/
tclm_1_0.lha
/
tclm-1.0
/
MLIB
/
mpu_bsd386.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-16
|
10KB
|
430 lines
/*-
* Copyright (c) 1993 Michael B. Durian. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Michael B. Durian.
* 4. The name of the the Author may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* mpu_bsd386.c,v 1.9 1993/05/07 17:45:20 durian Exp
*/
#ifdef MIDIPLAY
static char cvsid[] = "mpu_bsd386.c,v 1.9 1993/05/07 17:45:20 durian Exp";
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <i386/isa/midiioctl.h>
#include "mutil.h"
#include "mdevice.h"
#define MAX_EVENT_SIZE 256
/* global */
volatile int StopProcessing;
static int adjust_division _ANSI_ARGS_((int division, long *div_ioctl,
int *tempo_scalar));
static unsigned char double2tempo _ANSI_ARGS_((double d));
int
play_tracks(dev, tracks, indices, num, repeat)
int dev;
TCHUNK *tracks;
int *indices;
int num;
int repeat;
{
return (record_tracks(dev, tracks, indices, num, NULL, repeat));
}
int
record_tracks(dev, p_tracks, indices, p_num, r_track, repeat)
int dev;
TCHUNK *p_tracks;
int *indices;
int p_num;
TCHUNK *r_track;
int repeat;
{
TCHUNK tmptrack;
struct timeval mwait;
TCHUNK **track_list;
int *tscalars;
fd_set w_select;
fd_set r_select;
EVENT_TYPE event_type;
int endtime;
int event_len;
int i;
int select_return;
int track_done;
unsigned char event[MAX_EVENT_SIZE];
tscalars = NULL;
track_list = NULL;
if (p_num > 0) {
/* merge play tracks */
if ((tscalars = (int *)malloc(sizeof(int) * p_num)) == NULL) {
sprintf(MidiError, "Out of memory");
return (0);
}
if ((track_list = (TCHUNK **)malloc(sizeof(TCHUNK *) * p_num))
== NULL) {
sprintf(MidiError, "Out of memory");
return (0);
}
for (i = 0; i < p_num; i++) {
tscalars[i] = 1;
track_list[i] = &p_tracks[i];
}
init_track(&tmptrack);
endtime = merge_tracks(&tmptrack, track_list, tscalars, p_num,
0);
event_len = fix2var(endtime, event);
event[event_len] = METAEOT;
event[event_len + 1] = 0;
if (!put_smf_event(&tmptrack, event, event_len + 2)) {
sprintf(MidiError, "Couldn't add METAEOT event");
free(tscalars);
free(track_list);
free_track(&tmptrack);
return (0);
}
}
StopProcessing = 0;
do {
track_done = 0;
rewind_track(&tmptrack);
while (!StopProcessing && !track_done) {
/* select on play */
FD_ZERO(&w_select);
if (p_num != 0)
FD_SET(dev, &w_select);
/* also on record */
FD_ZERO(&r_select);
if (r_track != NULL)
FD_SET(dev, &r_select);
/*
* we time out every so often to check and see
* if StopProcessing has changed
*/
mwait.tv_sec = 0;
mwait.tv_usec = 100000;
if ((select_return = select(getdtablesize(), &r_select,
&w_select, NULL, &mwait)) == -1) {
if (errno == EINTR)
break;
else {
sprintf(MidiError,
"Error in select: %s",
sys_errlist[errno]);
if (tscalars != NULL)
free(tscalars);
if (track_list != NULL)
free(track_list);
free_track(&tmptrack);
return (0);
}
}
if (StopProcessing)
break;
if (select_return == 0)
continue;
/* write event if not blocked */
if (p_num != 0 && FD_ISSET(dev, &w_select)) {
event_len = get_smf_event(&tmptrack,
event, &event_type);
switch (event_len) {
case -1:
sprintf(MidiError,
"Couldn't get event from tmptrack");
if (tscalars != NULL)
free(tscalars);
if (track_list != NULL)
free(track_list);
free_track(&tmptrack);
return (0);
case 0:
track_done = 1;
break;
default:
if (write(dev, event, event_len) !=
event_len) {
sprintf(MidiError,
"Error writing event: %s",
sys_errlist[errno]);
if (tscalars != NULL)
free(tscalars);
if (track_list != NULL)
free(track_list);
free_track(&tmptrack);
return (0);
}
break;
}
}
if (r_track != NULL && FD_ISSET(dev, &r_select)) {
if ((event_len = read(dev, event,
MAX_EVENT_SIZE)) == -1) {
sprintf(MidiError,
"Error reading event: %s",
sys_errlist[errno]);
if (tscalars != NULL)
free(tscalars);
if (track_list != NULL)
free(track_list);
free_track(&tmptrack);
return (0);
}
if (!put_smf_event(r_track, event, event_len)) {
sprintf(MidiError,
"Coudln't put smf event");
if (tscalars != NULL)
free(tscalars);
if (track_list != NULL)
free(track_list);
free_track(&tmptrack);
return (0);
}
}
}
} while (repeat && !StopProcessing);
if (!StopProcessing) {
/* this waits until we're done playing */
if (ioctl(dev, MFLUSHQ, NULL) == -1)
sprintf(MidiError, "Error flushing queue: %s",
sys_errlist[errno]);
/* check for any final data to be read */
FD_ZERO(&r_select);
if (r_track != NULL)
FD_SET(dev, &r_select);
mwait.tv_sec = 0;
mwait.tv_usec = 0;
if ((select_return = select(getdtablesize(), NULL, &w_select,
NULL, &mwait)) == -1) {
if (errno != EINTR) {
sprintf(MidiError, "Error in select: %s",
sys_errlist[errno]);
if (tscalars != NULL)
free(tscalars);
if (track_list != NULL)
free(track_list);
free_track(&tmptrack);
return (0);
}
}
if (r_track != NULL && FD_ISSET(dev, &r_select)) {
if ((event_len = read(dev, event, MAX_EVENT_SIZE))
== -1) {
sprintf(MidiError, "Error reading event: %s",
sys_errlist[errno]);
if (tscalars != NULL)
free(tscalars);
if (track_list != NULL)
free(track_list);
free_track(&tmptrack);
return (0);
}
if (!put_smf_event(r_track, event, event_len)) {
sprintf(MidiError, "Coudln't put smf event");
if (tscalars != NULL)
free(tscalars);
if (track_list != NULL)
free(track_list);
free_track(&tmptrack);
return (0);
}
}
}
if (tscalars != NULL)
free(tscalars);
if (track_list != NULL)
free(track_list);
free_track(&tmptrack);
return (1);
}
int
stop_processing(dev)
int dev;
{
StopProcessing = 1;
/* if we leave, leave now - don't hang on close */
if (ioctl(dev, MCLRQ, NULL) == -1) {
sprintf(MidiError, "Error clearing queue: %s",
sys_errlist[errno]);
return (0);
}
return (0);
}
int
open_midi_device(mode)
PlayMode mode;
{
mode_t m;
int dev;
switch (mode) {
case PLAY:
m = O_WRONLY;
break;
case RECORD:
m = O_RDONLY;
break;
case PLAYRECORD:
m = O_RDWR;
break;
}
if ((dev = open("/dev/midi0", m)) == -1) {
sprintf(MidiError, "Couldn't open /dev/midi0: %s",
sys_errlist[errno]);
}
return (dev);
}
int
init_midi_device(dev, hd, reltempo)
int dev;
HCHUNK *hd;
double reltempo;
{
long div_ioctl;
int tscalar;
unsigned char fixreltempo;
if (!adjust_division(hd->division, &div_ioctl, &tscalar)) {
sprintf(MidiError, "Bad division value. Must be on of \
48, 72, 96, 120, 144, 168, 192 or an integer multiple thereof");
return (0);
}
if (ioctl(dev, div_ioctl, NULL) == -1) {
sprintf(MidiError, "Couldn't set division: %s",
sys_errlist[errno]);
return (0);
}
if (ioctl(dev, MTSCALAR, &tscalar) == -1) {
sprintf(MidiError, "Couldn't set tscalar: %s",
sys_errlist[errno]);
return (0);
}
fixreltempo = double2tempo(reltempo);
if (ioctl(dev, MSETRELTMP, &fixreltempo) == -1) {
sprintf(MidiError, "Couldn't set relative tempo: %s",
sys_errlist[errno]);
return (0);
}
return (1);
}
int
start_midi_device(dev, mode)
int dev;
PlayMode mode;
{
/* automatically started by open */
return (1);
}
int
stop_midi_device(dev, mode)
int dev;
PlayMode mode;
{
/* automatically stopped by close */
return (1);
}
int
close_midi_device(dev)
int dev;
{
close(dev);
return (1);
}
int
adjust_division(division, div_ioctl, tempo_scalar)
int division;
long *div_ioctl;
int *tempo_scalar;
{
long ioctls[] = {MRES192, MRES168, MRES144, MRES120, MRES96,
MRES72, MRES48};
int divs[] = {192, 168, 144, 120, 96, 72, 48};
int i;
int ret_val;
ret_val = 0;
for (i = 0; i < sizeof(divs) / sizeof(divs[0]); i++) {
if (division % divs[i] == 0) {
*div_ioctl = ioctls[i];
*tempo_scalar = 1000 * division / divs[i];
ret_val = 1;
break;
}
}
return (ret_val);
}
unsigned char
double2tempo(d)
double d;
{
double bit_vals[] = {2.0, 1.0, 0.5, 0.25, 0.125, 0.0625,
0.03125, 0.015625};
int i;
unsigned char tempo_scalar;
for (i = 0; i < 8; i++) {
if (d < bit_vals[i])
tempo_scalar = (tempo_scalar << 1) & ~1;
else {
tempo_scalar = (tempo_scalar << 1) | 1;
d -= bit_vals[i];
}
}
return(tempo_scalar);
}
#endif